"""
Service Manager for WebService

Handles creation and management of Kubernetes Service resources.
"""

import logging
from typing import Optional, Dict, Any
from kubernetes import client
from kubernetes.client.rest import ApiException

from .api import WebServiceSpec, ServiceStatus
from common import consts


class ServiceManagerError(Exception):
    """Service manager error"""
    pass


class ServiceManager:
    """Kubernetes Service resource management"""
    
    def __init__(self):
        """Initialize service manager"""
        self.logger = logging.getLogger(__name__)
        self.v1 = client.CoreV1Api()
        
    def create_service(self, webservice_spec: WebServiceSpec, webservice_name: str, webservice_namespace: str) -> str:
        """
        Create Service resource
        
        Args:
            webservice_spec: WebService specification object
            webservice_name: Name of the WebService for reference
            webservice_namespace: Namespace of the WebService
            
        Returns:
            Name of the created Service resource
            
        Raises:
            ServiceManagerError: If service creation fails
        """
        try:
            service_name = self._generate_service_name(webservice_name)
            
            self.logger.info(f"Creating service {service_name} for WebService {webservice_name}")
            
            # Create service object
            service = self._build_service_object(
                webservice_spec, service_name, webservice_name, webservice_namespace
            )
            
            # Create service in Kubernetes
            created_service = self.v1.create_namespaced_service(
                namespace=webservice_namespace,
                body=service
            )
            
            self.logger.info(f"Successfully created service {service_name}")
            return service_name
            
        except ApiException as e:
            error_msg = f"Failed to create service {service_name}: {e}"
            self.logger.error(error_msg)
            raise ServiceManagerError(error_msg) from e
        except Exception as e:
            error_msg = f"Unexpected error creating service {service_name}: {e}"
            self.logger.error(error_msg)
            raise ServiceManagerError(error_msg) from e
    
    def update_service(self, webservice_spec: WebServiceSpec, webservice_name: str, webservice_namespace: str) -> str:
        """
        Update existing Service resource
        
        Args:
            webservice_spec: WebService specification object
            webservice_name: Name of the WebService for reference
            webservice_namespace: Namespace of the WebService
            
        Returns:
            Name of the updated Service resource
            
        Raises:
            ServiceManagerError: If service update fails
        """
        try:
            service_name = self._generate_service_name(webservice_name)
            
            self.logger.info(f"Updating service {service_name} for WebService {webservice_name}")
            
            # Get existing service
            existing_service = self.v1.read_namespaced_service(
                name=service_name,
                namespace=webservice_namespace
            )
            
            # Build new service object
            new_service = self._build_service_object(
                webservice_spec, service_name, webservice_name, webservice_namespace
            )
            
            # Update service in Kubernetes
            updated_service = self.v1.patch_namespaced_service(
                name=service_name,
                namespace=webservice_namespace,
                body=new_service
            )
            
            self.logger.info(f"Successfully updated service {service_name}")
            return service_name
            
        except ApiException as e:
            error_msg = f"Failed to update service {service_name}: {e}"
            self.logger.error(error_msg)
            raise ServiceManagerError(error_msg) from e
        except Exception as e:
            error_msg = f"Unexpected error updating service {service_name}: {e}"
            self.logger.error(error_msg)
            raise ServiceManagerError(error_msg) from e
    
    def delete_service(self, webservice_name: str, webservice_namespace: str) -> bool:
        """
        Delete Service resource
        
        Args:
            webservice_name: Name of the WebService for reference
            webservice_namespace: Namespace of the WebService
            
        Returns:
            True if deletion was successful
            
        Raises:
            ServiceManagerError: If service deletion fails
        """
        try:
            service_name = self._generate_service_name(webservice_name)
            
            self.logger.info(f"Deleting service {service_name} for WebService {webservice_name}")
            
            # Delete service in Kubernetes
            self.v1.delete_namespaced_service(
                name=service_name,
                namespace=webservice_namespace
            )
            
            self.logger.info(f"Successfully deleted service {service_name}")
            return True
            
        except ApiException as e:
            if e.status == 404:
                self.logger.info(f"Service {service_name} not found, already deleted")
                return True
            error_msg = f"Failed to delete service {service_name}: {e}"
            self.logger.error(error_msg)
            raise ServiceManagerError(error_msg) from e
        except Exception as e:
            error_msg = f"Unexpected error deleting service {service_name}: {e}"
            self.logger.error(error_msg)
            raise ServiceManagerError(error_msg) from e
    
    def get_service_status(self, webservice_name: str, webservice_namespace: str) -> str:
        """
        Get Service status
        
        Args:
            webservice_name: Name of the WebService for reference
            webservice_namespace: Namespace of the WebService
            
        Returns:
            Status of the service
        """
        try:
            service_name = self._generate_service_name(webservice_name)
            
            # Get service object
            service = self.v1.read_namespaced_service(
                name=service_name,
                namespace=webservice_namespace
            )
            
            # Check if service exists
            if not service:
                return ServiceStatus.PENDING.value
            
            # Get service endpoints
            try:
                endpoints = self.v1.read_namespaced_endpoints(
                    name=service_name,
                    namespace=webservice_namespace
                )
                
                # Check if there are available endpoints
                if not endpoints.subsets or not endpoints.subsets[0].addresses:
                    return ServiceStatus.UNHEALTHY.value
                
                return ServiceStatus.HEALTHY.value
                
            except ApiException as e:
                if e.status == 404:
                    return ServiceStatus.PENDING.value  # Endpoints don't exist, waiting for pods
                else:
                    return ServiceStatus.UNKNOWN.value
            
        except ApiException as e:
            if e.status == 404:
                return ServiceStatus.UNHEALTHY.value  # Service doesn't exist, unhealthy state
            else:
                return ServiceStatus.UNKNOWN.value  # Other errors
        except Exception as e:
            self.logger.error(f"Error getting service status: {e}")
            return ServiceStatus.UNKNOWN.value
    
    def _generate_service_name(self, webservice_name: str) -> str:
        """Generate service name from WebService name"""
        return f"{webservice_name}-service"
    
    def _build_service_object(self, webservice_spec: WebServiceSpec, service_name: str, 
                            webservice_name: str, webservice_namespace: str) -> Dict:
        """Build Kubernetes Service object"""
        service_spec = webservice_spec.service
        
        # Build port specs
        ports = []
        for port in service_spec.ports:
            port_dict = {
                "name": port.name,
                "port": port.port,
                "targetPort": port.target_port,
                "protocol": port.protocol.value if port.protocol else "TCP"
            }
            ports.append(port_dict)
        
        # Build service object
        service = {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "name": service_name,
                "namespace": webservice_namespace,
                   "labels": {
                       "app": webservice_name,
                       "webservice": webservice_name,
                       "managed-by": consts.APPLICATION_NAME
                   }
            },
            "spec": {
                "type": service_spec.type.value if service_spec.type else "ClusterIP",
                "selector": {
                    "app": webservice_name,
                    "webservice": webservice_name
                },
                "ports": ports
            }
        }
        
        return service
